package com.chatTools.server;

import com.chatTools.handler.*;
import com.chatTools.protocol.MessageCodecSharable;
import com.chatTools.protocol.ProtocolFrameDecoder;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;

/**
 * @author： pang-yun
 * @date： 2021-09-16 15:09
 * 功能目的 ：用于  聊天工具的服务器端
 */
@Slf4j
public class ChatServer {


    public static void main(String[] args) {
        NioEventLoopGroup boss = new NioEventLoopGroup();
        NioEventLoopGroup worker = new NioEventLoopGroup();

        // 各类处理器
        //---- 第一个帧处理器 不能在 服务器端 中 提取出来使用    可以在客户端中提取出来
        ProtocolFrameDecoder PROTOCOL_FRAME_DECODER = new ProtocolFrameDecoder();
        LoggingHandler LOGGING_HANDLER = new LoggingHandler(LogLevel.INFO);
        MessageCodecSharable MESSAGE_CODEC_SHARABLE = new MessageCodecSharable();
        LoginRequestMessageHandler LOGIN_HANDLER = new LoginRequestMessageHandler();
        ChatRequestMessageHandler CHAT_HANDLER = new ChatRequestMessageHandler();
        // 创建群聊
        GroupCreateRequestMessageHandler GROUP_CREATE_HANDLER = new GroupCreateRequestMessageHandler();
        //群聊聊天
        GroupChatRequestMessageHandler GROUP_CHAT_HANDLER = new GroupChatRequestMessageHandler();
        // 获取 群所有成员
        GroupMemberRequestMessageHandler GROUP_MEMBER_HANDLER = new GroupMemberRequestMessageHandler();
        // 退出群聊
        GroupQuitRequestMessageHandler GROUP_QUIT_HANDLER = new GroupQuitRequestMessageHandler();
        // 断开处理
        QuitHandler QUIT_HANDLER = new QuitHandler();
        try {
            ChannelFuture channelFuture = new ServerBootstrap()
                    .group(boss, worker)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel ch) throws Exception {
//--------------------------------------编解码--------------------------------------------------------------------------
                            // 确保就算出现 半包 也能读取到 完整数据
                            //  ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(1024, 12, 4, 0, 0));
                            // 防止别人改错  将其提取到 ProtocolFrameDecoder
                            //-----------??????????  为什么不能提取出来--------
                            // ch.pipeline().addLast(PROTOCOL_FRAME_DECODER);
                            ch.pipeline().addLast(new ProtocolFrameDecoder());

                            //    ch.pipeline().addLast(LOGGING_HANDLER);
                            // 因为前面 经过 帧解码器 处理  这步得到的是完整的消息， 不存在线程安全问题  可以将 这个提取出来全局使用
                            ch.pipeline().addLast(MESSAGE_CODEC_SHARABLE);

//----------------------------------空闲事件处理------------------------------------------------------------------------
                            //假死时间处理 判断是否 读写时间过长   (read write all)
                            // 5s 之内如果没有收到 channel的数据， 就会触发一个 IdleState.READER_IDLE 事件
                            ch.pipeline().addLast(new IdleStateHandler(5, 0, 0));
                            // 触发假死 事件之后来进行处理    ChannelDuplexHandler  双向处理器
                            ch.pipeline().addLast(new ChannelDuplexHandler() {
                                // trigger 触发器     用来触发特殊事件
                                @Override
                                public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
                                    IdleStateEvent event = (IdleStateEvent) evt;
                                    // 出发了空闲事件
                                    if (event.state() == IdleState.READER_IDLE) {
                                        log.info("已经 5s 没有读到空闲的数据了！！！");
                                    }
                                }
                            });

                            //----------------------------------------------------------------------


                            //--------------------业务---------
                            ch.pipeline().addLast(LOGIN_HANDLER); // 登录处理器
                            ch.pipeline().addLast(CHAT_HANDLER); //  聊天处理器
                            ch.pipeline().addLast(GROUP_CREATE_HANDLER);  // 创建群聊处理器
                            ch.pipeline().addLast(GROUP_CHAT_HANDLER); // 聊天
                            ch.pipeline().addLast(GROUP_MEMBER_HANDLER); // 成员
                            ch.pipeline().addLast(GROUP_QUIT_HANDLER); // 退出群聊
                            ch.pipeline().addLast(QUIT_HANDLER); // 断开处理

                        }
                    }).bind(9999).sync();
            channelFuture.channel().closeFuture().sync();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }

}
